/***************************************************************************
  A SymbolBrowser plugin for JuffEd editor.

  Copyright: 2010 Aleksander Sokoloff <asokol@mail.ru>


  This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License.
  version 2 as published by the Free Software Foundation.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software Foundation,
  Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
***************************************************************************/

#include "documentparser.h"
#include "symbolbrowserview.h"
#include "parserthread.h"
#include "symbol.h"

#include <QDebug>
#include <QTimerEvent>
//#include <QScrollBar>


#define DELAY_INTERVAL 250



/**********************************************************
 *
 **********************************************************/
DocumentParser::DocumentParser(SymbolBrowserView *view, QObject * parent)
: QObject(parent)
{
    mView = view;
    if (mView->settingsSort())
        mSortedBy = Item::SortByName;
    else
        mSortedBy = Item::SortByLine;

    mDetailed = mView->settingsDetail();
    lastParser = NULL;
}


/**********************************************************
 *
 **********************************************************/
DocumentParser::~DocumentParser()
{
    if (mView && mView->mActiveParser == this)
        mView->mActiveParser = NULL;
}


/**********************************************************
 *
 **********************************************************/
bool DocumentParser::isActive() const
{
    return mView && (mView->mActiveParser == this);
}


/**********************************************************
 *
 **********************************************************/
void DocumentParser::activate()
{
    if (!mView) return;

    if (mView->mActiveParser)
        mView->mActiveParser->saveState();

    mView->mActiveParser = this;
    doRefresh();
}


/**********************************************************
 *
 **********************************************************/
void DocumentParser::refresh()
{
    delayTimerId = startTimer(DELAY_INTERVAL);
}


/**********************************************************
 *
 **********************************************************/
void DocumentParser::timerEvent(QTimerEvent *event)
{
    killTimer(event->timerId());
    if (delayTimerId == event->timerId())
        doRefresh();
}


/**********************************************************
 *
 **********************************************************/
void DocumentParser::doRefresh()
{
    if (lastParser)
        lastParser->stop();

    lastParser = new ParserThread();
    connect(lastParser, SIGNAL(finished()), this, SLOT(onParserFinished()));

    QString text;
    getText(text);
    lastParser->setLanguage(language());
    lastParser->setText(text);
    lastParser->start();
}


/**********************************************************
 *
 **********************************************************/
void DocumentParser::onParserFinished() {
    ParserThread *parser = qobject_cast<ParserThread*>(sender());

    if (! parser ) return;

    if (parser == lastParser) {
        if (mView)
        {
            saveState();
            mView->mModel->setSortRole(Qt::UserRole + mSortedBy);
            mView->mModel->removeRows(0, mView->mModel->invisibleRootItem()->rowCount(), QModelIndex());
            rebuildChildren(parser->symbols(), mView->mModel->invisibleRootItem(), "/");
        }

        sort(mSortedBy);
        lastParser = NULL;
    }

    delete parser;
}


/**********************************************************
 *
 **********************************************************/
void DocumentParser::rebuildChildren(Symbol *parentSymbol, QStandardItem *parentItem, const QString &path)
{
    SymbolIterator s;
    for (s = parentSymbol->begin(); s != parentSymbol->end(); ++s)
    {
        Item *item;
        switch ((*s)->type()) {
            case SymbolTypeClass:     item = new ItemClass(*s);       break;
            case SymbolTypeStruct:    item = new ItemStruct(*s);      break;
            case SymbolTypeFunc:      item = new ItemFunc(*s);        break;
            case SymbolTypeNamespace: item = new ItemNamespace(*s);   break;
            case SymbolTypePrototype: item = new ItemPrototype(*s);   break;
            default:                  item = new Item(*s);
        }

        item->setPath(path + item->name() + "/");
        parentItem->appendRow(item);
        rebuildChildren(*s, item, item->path());

        bool expanded = false;
        if (mItemStatesByPath.contains(item->path()))
            expanded =  mItemStatesByPath[item->path()];
        else if (mItemStatesByLine.contains(item->line()))
            expanded = mItemStatesByLine[item->line()];
        else
            expanded = mView->settingsExpand();

        mView->mTreeView->setExpanded(item->index(), expanded);
        item->setDetailed(mDetailed);
    }
}


/**********************************************************
 *
 **********************************************************/
void DocumentParser::saveState()
{
    if (!mView) return;

    saveItemStates(mView->mModel->invisibleRootItem());
}


/**********************************************************
 *
 **********************************************************/
void DocumentParser::saveItemStates(QStandardItem *parentItem)
{
    int cnt = parentItem->rowCount();
    for (int i=0; i<cnt; ++i)
    {
        Item *item = dynamic_cast<Item*>(parentItem->child(i, 0));
        if (item)
        {
            bool expanded = mView->mTreeView->isExpanded(item->index());
            mItemStatesByPath[item->path()] = expanded;
            mItemStatesByLine[item->line()] = expanded;
        }
        saveItemStates(item);
    }
}


/**********************************************************
 *
 **********************************************************/
void DocumentParser::sort(Item::SortOrder order)
{
    mSortedBy = order;

    mView->mModel->setSortRole(Qt::UserRole + order);

    QStandardItem *rootItem = mView->mModel->invisibleRootItem();
    rootItem->sortChildren(0, Qt::AscendingOrder);

}


/**********************************************************
 *
 **********************************************************/
void DocumentParser::setDetailed(bool value)
{
    mDetailed = value;

    QStandardItem *rootItem = mView->mModel->invisibleRootItem();
    int cnt = rootItem->rowCount();
    for (int i=0; i<cnt; ++i)
    {
        Item *item = dynamic_cast<Item*>(rootItem->child(i, 0));
        if (item)
            item->setDetailed(value);
    }

}
